package com.gitee.melin.bee.core.jdbc.dialect.oceanbase;

import com.gitee.melin.bee.core.jdbc.dialect.DefaultTypeConvertor;
import com.gitee.melin.bee.core.jdbc.dialect.mysql.MySqlTypeConvertor;
import com.gitee.melin.bee.core.jdbc.enums.DataSourceType;
import com.gitee.melin.bee.core.jdbc.dialect.DataTypeConvertor;
import com.gitee.melin.bee.core.jdbc.dialect.AbstractJdbcDialect;
import com.gitee.melin.bee.core.jdbc.dialect.IDBQuery;
import com.gitee.melin.bee.core.jdbc.dialect.oracle.OracleQuery;
import com.gitee.melin.bee.core.jdbc.relational.ConnectionInfo;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.Driver;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

public class OceanBaseJdbcDialect extends AbstractJdbcDialect {

    private static final Logger LOG = LoggerFactory.getLogger(OceanBaseJdbcDialect.class);

    public OceanBaseJdbcDialect(ConnectionInfo connectionInfo) {
        super(connectionInfo);
    }

    public OceanBaseJdbcDialect(Connection connection) {
        super(connection);
    }

    @Override
    public DataSourceType getDataSourceType() {
        return DataSourceType.OCEANBASE;
    }

    @Override
    protected IDBQuery getDBQuery() {
        if ("ORACLE".equalsIgnoreCase(compatibleMode)){
            return new OracleQuery();
        } else {
            return new OceanBaseQuery();
        }
    }

    @Override
    protected DataTypeConvertor getTypeConvert() {
        if ("ORACLE".equalsIgnoreCase(compatibleMode)){
            return new DefaultTypeConvertor();
        } else {
            return new MySqlTypeConvertor();
        }
    }

    @Override
    protected void connectionProperties(Map<String, String> connectionProperties) {
        connectionProperties.put("useInformationSchema", "true");
        connectionProperties.put("useUnicode", "true");
        connectionProperties.put("characterEncoding", "utf8");
        connectionProperties.put("tinyInt1isBit", "false");
        connectionProperties.put("rewriteBatchedStatements", "true");
        connectionProperties.put("connectTimeout", "10000"); // 10s
    }

    @Override
    protected Driver getDriver() {
        try {
            Class<?> clazz = Class.forName(DataSourceType.OCEANBASE.getDriverClass());
            return (Driver) clazz.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    @Override
    protected boolean filterSchema(String schemaName) {
        if (schemaName.equalsIgnoreCase("mysql")
                || schemaName.equalsIgnoreCase("oceanbase") || schemaName.equalsIgnoreCase("__public") || schemaName.equalsIgnoreCase("LBACSYS") || schemaName.equalsIgnoreCase("ORAAUDITOR")) {
            return false;
        }
        return super.filterSchema(schemaName);
    }

    @Override
    public List<String> listSchemas(Connection connection) {
        if ("ORACLE".equalsIgnoreCase(compatibleMode)){
            return super.listSchemas(connection);
        }

        // for MySQL, we need to list catalogs instead of schemas
        try (ResultSet resultSet = connection.getMetaData().getCatalogs()) {
            List<String> schemas = Lists.newArrayList();
            while (resultSet.next()) {
                String schemaName = resultSet.getString("TABLE_CAT");
                // skip internal schemas
                if (filterSchema(schemaName)) {
                    schemas.add(schemaName);
                }
            }
            return schemas;
        } catch (SQLException e) {
            throw new RuntimeException("Get Scheme Error", e);
        }
    }

    @Override
    protected String getDDLColumnName() {
        return "Create Table";
    }
}
